#ifndef THREADPOOL__HPP_
#define THREADPOOL__HPP_

#include <iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<queue>
#include<list>
#include<functional>
#include <atomic>
#define sleeptime 3

class ThreadPool
{
private:
    std::queue<std::function<void()>> taskque;
    std::list<std::thread> threads;
    std::atomic<int> max_threadnum;
    std::atomic<int> min_threadnum;
    std::atomic<int> max_quesize;
    std::atomic<int> bsy_threadnum;
    std::atomic<int> kill_threadnum;
    std::atomic<bool> shutdown;
    std::mutex poolmtx;
    std::mutex bsy_threadnum_mtx;
    std::mutex kill_threadnum_mtx;
    std::condition_variable que_notEmpty;
    std::condition_variable que_notFull;
    std::thread manager;
public:
    ThreadPool(int max_threadnum,int min_threadnum,int max_quesize);
    ~ThreadPool();
    void Thread_manager();
    void Thread_handler();

    template <typename F, typename... Args>
    void AddPoolTask(F &&f, Args && ...args);
};

ThreadPool::ThreadPool(int max_threadnum, int min_threadnum, int max_quesize):
max_threadnum(max_threadnum),
min_threadnum(min_threadnum),
max_quesize(max_quesize),
bsy_threadnum(0),
kill_threadnum(0),
shutdown(false)
{
    manager= std::thread(&ThreadPool::Thread_manager, this);
    for (int i = 0; i < max_threadnum; i++)
    {
        threads.push_back(std::thread(&ThreadPool::Thread_handler, this));
    }
}

ThreadPool::~ThreadPool()
{
    
    
    que_notEmpty.notify_all();
    
    for (auto &thread : threads)
    {
        if (thread.joinable())
        {
            thread.join();
        }
    }
    if (manager.joinable())
    {
        manager.join();
    }

    {
        std::unique_lock<std::mutex> lock(poolmtx);
        shutdown = true; 
    }
}

void ThreadPool::Thread_manager()
{
    while (shutdown==false)
    {
        std::this_thread::sleep_for(std::chrono::seconds(sleeptime));
        std::unique_lock<std::mutex> lock(poolmtx);
        int quelen=taskque.size();
        if (bsy_threadnum/2 <= quelen && bsy_threadnum < max_threadnum)
        {
            int addnum = quelen > (max_threadnum - threads.size())?quelen:(max_threadnum - threads.size());
            for (int i = 0; i < addnum; i++)
            {
                threads.push_back(std::thread(&ThreadPool::Thread_handler, this));
            }
        }
        bsy_threadnum_mtx.lock();
        if (bsy_threadnum * 2 < threads.size() && threads.size() > min_threadnum)
        {
            kill_threadnum_mtx.lock();
            kill_threadnum=((threads.size()-bsy_threadnum)/2)<(threads.size()-min_threadnum)?(threads.size()-bsy_threadnum)/2:(threads.size()-min_threadnum);
            bsy_threadnum_mtx.unlock();
            for (int i = 0; i < kill_threadnum; i++)
            {
                kill_threadnum_mtx.unlock();
                que_notEmpty.notify_one();
            }
        }
        else
            bsy_threadnum_mtx.unlock();
    }
}

void ThreadPool::Thread_handler()
{
    while (1)
    {
        std::unique_lock<std::mutex> lock(poolmtx);
        while (taskque.empty() && shutdown == false)
        {
            que_notEmpty.wait(lock);
            kill_threadnum_mtx.lock();
            if (kill_threadnum==0)
            {
                kill_threadnum_mtx.unlock();
            }
            else if(kill_threadnum>0)
            {
                kill_threadnum--;
                kill_threadnum_mtx.unlock();
                return;
            }
        }

        if(shutdown==true)
        {
            return;
        }

        std::function<void()> task = std::move(taskque.front());
        taskque.pop();
        que_notFull.notify_one();
        lock.unlock();
        bsy_threadnum_mtx.lock();
        bsy_threadnum++;
        bsy_threadnum_mtx.unlock();
        task();
        bsy_threadnum_mtx.lock();
        bsy_threadnum--;
        bsy_threadnum_mtx.unlock();
    }
    
}
template <typename F, typename... Args>
void ThreadPool::AddPoolTask(F&& func, Args&&...args)
{
    std::unique_lock<std::mutex> lock(poolmtx);
    std::cout << "已上线程池锁\n"<< std::endl;
    if (shutdown)
    {
        lock.unlock();
        return;
    }  
    
    while(taskque.size() >= max_quesize)
        {
            que_notFull.wait(lock);
        }
    std::cout<<"创建新任务压入队列\n"<<std::endl;
    auto task = std::bind(std::forward<F>(func), std::forward<Args>(args)...);
    taskque.emplace(std::move(task));
    que_notEmpty.notify_one();
}

#endif